মাল্টিথ্রেডিং এবং কনকারেন্সি সি প্রোগ্রামিং ভাষায় একাধিক কাজ একযোগে সম্পাদনের জন্য ব্যবহৃত হয়। মাল্টিথ্রেডিং একটি প্রক্রিয়ায় একাধিক থ্রেড তৈরি করে বিভিন্ন কাজ একই সময়ে সম্পন্ন করে, যেখানে কনকারেন্সি হলো একাধিক কাজের মধ্যে সঠিকভাবে ক্রম তৈরি করার কৌশল।
মাল্টিথ্রেডিং হলো একই প্রক্রিয়ার অধীনে একাধিক থ্রেড তৈরি করে একাধিক কাজ করার প্রক্রিয়া। প্রতিটি থ্রেড একই অ্যাড্রেস স্পেস ভাগ করে এবং প্রোগ্রামের আলাদা অংশ সম্পন্ন করে। এটি প্রোগ্রামের গতি বৃদ্ধি করে এবং প্রসেসরের ক্ষমতা সর্বোচ্চ পর্যায়ে পৌঁছে দেয়।
সি প্রোগ্রামে মাল্টিথ্রেডিং বাস্তবায়নের জন্য POSIX Threads (Pthreads) ব্যবহার করা হয়। এটি একটি পোর্টেবল থ্রেডিং লাইব্রেরি, যা থ্রেড তৈরি, পরিচালনা, এবং সমন্বয় করতে ব্যবহৃত হয়। pthread.h
হেডার ফাইলের মাধ্যমে Pthreads ফাংশনগুলো ব্যবহৃত হয়।
ফাংশন | কাজ |
---|---|
pthread_create() | নতুন থ্রেড তৈরি করে |
pthread_join() | একটি থ্রেড শেষ হওয়া পর্যন্ত অপেক্ষা করে |
pthread_exit() | থ্রেড থেকে বেরিয়ে যায় |
pthread_cancel() | একটি থ্রেড বন্ধ করে |
pthread_mutex_lock() | মিউটেক্স লক সেট করে |
pthread_mutex_unlock() | মিউটেক্স আনলক করে |
pthread_create()
– থ্রেড তৈরি করাpthread_create()
ফাংশনটি একটি নতুন থ্রেড তৈরি করতে ব্যবহৃত হয়। এটি থ্রেডের জন্য একটি ফাংশন এবং আর্গুমেন্ট গ্রহণ করে এবং থ্রেডটি তৈরি হলে সেই ফাংশনটি কার্যকর হয়।
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void *print_message(void *arg) {
printf("Hello from thread!\n");
return NULL;
}
int main() {
pthread_t thread;
// নতুন থ্রেড তৈরি করা
pthread_create(&thread, NULL, print_message, NULL);
// থ্রেড শেষ হওয়ার জন্য অপেক্ষা করা
pthread_join(thread, NULL);
printf("Hello from main!\n");
return 0;
}
Output:
Hello from thread!
Hello from main!
Note:
pthread_join()
মূল থ্রেডকে নতুন থ্রেড শেষ হওয়া পর্যন্ত অপেক্ষা করতে বাধ্য করে।
pthread_join()
– থ্রেডের সমাপ্তির জন্য অপেক্ষাpthread_join()
ফাংশনটি মূল থ্রেডকে নির্দিষ্ট থ্রেডের সমাপ্তি পর্যন্ত অপেক্ষা করতে বাধ্য করে।
int pthread_join(pthread_t thread, void **retval);
pthread_mutex_lock()
এবং pthread_mutex_unlock()
– মিউটেক্স লকমাল্টিথ্রেডিং প্রোগ্রামে একাধিক থ্রেড একই ডেটায় একযোগে কাজ করলে রেস কন্ডিশন তৈরি হতে পারে। এটি এড়াতে মিউটেক্স (Mutex) ব্যবহার করা হয়, যা থ্রেডকে একে অপরের সাথে সমন্বয় করতে সহায়ক।
pthread_mutex_lock()
ফাংশনটি মিউটেক্স লক করে, অর্থাৎ নির্দিষ্ট থ্রেডকে একটি ক্রিটিকাল সেকশনে এককভাবে কাজ করার অনুমতি দেয়।pthread_mutex_unlock()
ফাংশনটি মিউটেক্স আনলক করে, যাতে অন্য থ্রেড ক্রিটিকাল সেকশনে প্রবেশ করতে পারে।#include <stdio.h>
#include <pthread.h>
int counter = 0;
pthread_mutex_t lock;
void *increment_counter(void *arg) {
pthread_mutex_lock(&lock); // লক করা
counter++;
printf("Counter: %d\n", counter);
pthread_mutex_unlock(&lock); // আনলক করা
return NULL;
}
int main() {
pthread_t thread1, thread2;
pthread_mutex_init(&lock, NULL); // মিউটেক্স ইনিশিয়ালাইজ করা
pthread_create(&thread1, NULL, increment_counter, NULL);
pthread_create(&thread2, NULL, increment_counter, NULL);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
pthread_mutex_destroy(&lock); // মিউটেক্স ধ্বংস করা
return 0;
}
Output: (Output may vary due to thread scheduling)
Counter: 1
Counter: 2
কনকারেন্সি হলো একাধিক কাজ বা প্রসেসকে এমনভাবে সমন্বয় করা, যাতে তারা একে অপরের সাথে সংঘর্ষে না আসে। মাল্টিথ্রেডিং এবং কনকারেন্সি একে অপরের সাথে সম্পর্কিত, তবে কনকারেন্সি শুধু মাল্টিথ্রেডিংয়ে নয় বরং সিঙ্গল-থ্রেড অ্যাপ্লিকেশনেও দেখা যেতে পারে।
কনকারেন্সি সাধারণত তখনই ব্যবহৃত হয় যখন একাধিক থ্রেড বা প্রসেস একই রিসোর্সে কাজ করে। উদাহরণস্বরূপ, ব্যাংকিং সফটওয়্যারে একই অ্যাকাউন্ট থেকে একাধিক লেনদেন কনকারেন্টলি (একযোগে) করতে গেলে রেস কন্ডিশন তৈরি হতে পারে। এ ধরনের সমস্যা এড়াতে লক এবং সিঙ্ক্রোনাইজেশন কৌশল ব্যবহার করতে হয়।
১. দ্রুত ডেটা প্রক্রিয়াকরণ: একাধিক থ্রেড ব্যবহার করে প্রোগ্রামের কার্যক্ষমতা বৃদ্ধি পায়।
২. সমান্তরাল ডেটা প্রসেসিং: বিভিন্ন ডেটা সমান্তরালে প্রসেস করা সম্ভব হয়।
৩. রেস কন্ডিশন হ্রাস: মিউটেক্স ও লক ব্যবহার করে থ্রেডের মধ্যে সংঘর্ষ কমানো সম্ভব।
৪. ব্যবহারকারীর অভিজ্ঞতা উন্নত: একই সময়ে একাধিক কাজের জন্য অপেক্ষা কমে যায় এবং ব্যবহারকারীর অভিজ্ঞতা উন্নত হয়।
ফাংশন | কাজ |
---|---|
pthread_create() | নতুন থ্রেড তৈরি করে |
pthread_join() | নির্দিষ্ট থ্রেড শেষ হওয়া পর্যন্ত অপেক্ষা করে |
pthread_mutex_lock() | মিউটেক্স লক করে এবং থ্রেডকে একক অ্যাক্সেস দেয় |
pthread_mutex_unlock() | মিউটেক্স আনলক করে, যাতে অন্য থ্রেড অ্যাক্সেস পায় |
মাল্টিথ্রেডিং এবং কনকারেন্সি সি প্রোগ্রামিংয়ে প্রোগ্রামিং দক্ষতা বৃদ্ধি করে এবং প্রসেসরের কার্যক্ষমতা সর্বাধিক করে। Pthreads লাইব্রেরি ব্যবহার করে মাল্টিথ্রেডিং বাস্তবায়ন করা সহজ হয় এবং মিউটেক্স ও লক ব্যবহার করে কনকারেন্সি সমস্যা সমাধান করা যায়।
pthread.h
এবং POSIX Thread Library এর প্রয়োগpthread.h
হেডার ফাইলটি সি প্রোগ্রামিং ভাষায় POSIX থ্রেড লাইব্রেরি (Portable Operating System Interface Threads Library) ব্যবহারের জন্য ব্যবহৃত হয়। POSIX থ্রেড লাইব্রেরি সি প্রোগ্রামিংয়ে মাল্টিথ্রেডিং কার্যকারিতা যোগ করার একটি স্ট্যান্ডার্ড উপায়। মাল্টিথ্রেডিং এমন একটি কৌশল, যার মাধ্যমে প্রোগ্রাম একাধিক অংশে বিভক্ত হয়ে সমান্তরালভাবে কাজ করতে পারে, যা সিপিইউর কার্যক্ষমতা এবং প্রোগ্রামের কর্মদক্ষতা বৃদ্ধি করে।
১. সমান্তরাল প্রক্রিয়াকরণ: একাধিক কাজ সমান্তরালে চালাতে থ্রেড ব্যবহার করা হয়, যা প্রোগ্রামের পারফরম্যান্স বৃদ্ধি করে।
২. CPU রিসোর্সের সর্বোচ্চ ব্যবহার: মাল্টিপ্রসেসর সিস্টেমে বিভিন্ন থ্রেড আলাদা আলাদা কোরে চলতে পারে, যা CPU-এর রিসোর্সের সর্বোচ্চ ব্যবহার নিশ্চিত করে।
৩. প্রোগ্রামের প্রতিক্রিয়াশীলতা বৃদ্ধি: মাল্টিথ্রেডিংয়ের মাধ্যমে প্রোগ্রাম আরও দ্রুত এবং প্রতিক্রিয়াশীল হয়, কারণ থ্রেডগুলো সমান্তরালে কাজ করতে পারে।
৪. ডেটা শেয়ারিং: একাধিক থ্রেড সহজেই একে অপরের ডেটা শেয়ার এবং অ্যাক্সেস করতে পারে, যা মাল্টিপ্রসেসিংয়ের তুলনায় আরও কার্যকর।
pthread.h
এর গুরুত্বপূর্ণ ফাংশনসমূহpthread.h
হেডার ফাইলে কিছু গুরুত্বপূর্ণ ফাংশন রয়েছে যা থ্রেড তৈরি, থ্রেড পরিচালনা, এবং থ্রেড সিঙ্ক্রোনাইজেশন করতে ব্যবহৃত হয়। নিচে তাদের ব্যাখ্যা দেওয়া হলো।
pthread_create()
– থ্রেড তৈরি করাpthread_create()
ফাংশনটি একটি নতুন থ্রেড তৈরি করতে ব্যবহৃত হয় এবং এটি সফলভাবে তৈরি হলে থ্রেডের ID রিটার্ন করে।
সিঙ্কট্যাক্স:
int pthread_create(pthread_t *thread, const pthread_attr_t *attr, void *(*start_routine)(void *), void *arg);
thread
: থ্রেড আইডি সঞ্চয় করতে পয়েন্টার।attr
: থ্রেডের বৈশিষ্ট্য নির্ধারণ করতে ব্যবহৃত (NULL হলে ডিফল্ট বৈশিষ্ট্য)।start_routine
: থ্রেডের মেইন ফাংশন বা কাজের ফাংশনের পয়েন্টার।arg
: থ্রেডের মেইন ফাংশনে পাস করা আর্গুমেন্ট।#include <stdio.h>
#include <stdlib.h>
#include <pthread.h>
void *print_message(void *message) {
printf("%s\n", (char *)message);
return NULL;
}
int main() {
pthread_t thread;
const char *message = "Hello, Thread!";
// থ্রেড তৈরি
if (pthread_create(&thread, NULL, print_message, (void *)message)) {
fprintf(stderr, "Error creating thread\n");
return 1;
}
// থ্রেডের সমাপ্তির জন্য অপেক্ষা
pthread_join(thread, NULL);
return 0;
}
pthread_join()
– থ্রেড সমাপ্তির জন্য অপেক্ষা করাpthread_join()
ফাংশনটি একটি নির্দিষ্ট থ্রেড শেষ হওয়া পর্যন্ত অপেক্ষা করতে ব্যবহৃত হয়। এটি থ্রেড সিঙ্ক্রোনাইজেশনের জন্য গুরুত্বপূর্ণ।
সিঙ্কট্যাক্স:
int pthread_join(pthread_t thread, void **retval);
thread
: যে থ্রেডটির জন্য অপেক্ষা করতে হবে তার ID।retval
: থ্রেডের রিটার্ন মান সঞ্চয় করার জন্য পয়েন্টার।pthread_exit()
– থ্রেড শেষ করাpthread_exit()
ফাংশনটি একটি থ্রেডের কার্যকলাপ শেষ করতে ব্যবহৃত হয়। এটি অন্য থ্রেডের কার্যক্রমে কোনো ব্যাঘাত না ঘটিয়ে বর্তমান থ্রেড শেষ করে।
সিঙ্কট্যাক্স:
void pthread_exit(void *retval);
retval
: থ্রেডের রিটার্ন মান।void *my_thread(void *arg) {
printf("Thread is running\n");
pthread_exit(NULL); // থ্রেড শেষ করা
}
pthread_mutex_t
– মিউটেক্স লকমাল্টিথ্রেডিংয়ের সময় ডেটা রেস বা একাধিক থ্রেড একই ডেটা অ্যাক্সেস করলে সমস্যা দেখা দিতে পারে। এই সমস্যা সমাধানে মিউটেক্স লক (Mutex Lock) ব্যবহার করা হয়, যা একটি নির্দিষ্ট সময়ে একাধিক থ্রেডের একই ডেটা অ্যাক্সেস করা বন্ধ করে।
মিউটেক্স ব্যবহারের ফাংশনসমূহ:
pthread_mutex_init()
– মিউটেক্স লক আরম্ভ করা।pthread_mutex_lock()
– মিউটেক্স লক করা।pthread_mutex_unlock()
– মিউটেক্স আনলক করা।pthread_mutex_destroy()
– মিউটেক্স লক ধ্বংস করা।#include <stdio.h>
#include <pthread.h>
pthread_mutex_t lock; // মিউটেক্স লক ডিক্লেয়ার
void *increment_counter(void *arg) {
pthread_mutex_lock(&lock); // লক করা
int *counter = (int *)arg;
(*counter)++;
printf("Counter: %d\n", *counter);
pthread_mutex_unlock(&lock); // আনলক করা
return NULL;
}
int main() {
pthread_t thread1, thread2;
int counter = 0;
pthread_mutex_init(&lock, NULL); // মিউটেক্স আরম্ভ করা
pthread_create(&thread1, NULL, increment_counter, &counter);
pthread_create(&thread2, NULL, increment_counter, &counter);
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
pthread_mutex_destroy(&lock); // মিউটেক্স ধ্বংস করা
return 0;
}
ফাংশন | কাজ |
---|---|
pthread_self() | বর্তমান থ্রেডের ID রিটার্ন করে। |
pthread_equal() | দুটি থ্রেডের ID সমান কিনা তা যাচাই করে। |
pthread_cancel() | একটি থ্রেড বাতিল করতে ব্যবহৃত হয়। |
pthread_detach() | থ্রেডকে পৃথক বা detached করার জন্য ব্যবহৃত হয়। |
pthread_attr_init() | থ্রেড অ্যাট্রিবিউট আরম্ভ করার জন্য ব্যবহৃত হয়। |
POSIX থ্রেড লাইব্রেরি মাল্টিথ্রেডেড প্রোগ্রামিংয়ের জন্য সি প্রোগ্রামিংয়ে একটি মানসম্মত উপায় সরবরাহ করে। pthread.h
হেডার ফাইলটি ব্যবহার করে মাল্টিথ্রেডেড প্রোগ্রাম তৈরি করা যায়, যা কর্মদক্ষতা বৃদ্ধি এবং CPU রিসোর্সের সর্বোত্তম ব্যবহার নিশ্চিত করে।
Pthreads লাইব্রেরির মাধ্যমে থ্রেড তৈরি, থ্রেডের মধ্যে সমন্বয় এবং সিঙ্ক্রোনাইজেশন সহজেই করা সম্ভব, যা জটিল প্রোগ্রামিং পরিবেশে কর্মক্ষমতা উন্নত করতে সহায়ক।
সি প্রোগ্রামিং ভাষায় থ্রেড ব্যবহার এবং মিউটেক্স (mutex) হ্যান্ডলিং সাধারণত POSIX Threads (pthreads) লাইব্রেরি ব্যবহার করে করা হয়। থ্রেড তৈরি, সিঙ্ক্রোনাইজেশন এবং মিউটেক্স ব্যবহৃত হয় বহুসংখ্যক থ্রেডের মধ্যে সঠিকভাবে কাজ করতে এবং মেমোরি রেস কন্ডিশন (race condition) এড়াতে। নিচে থ্রেড তৈরি, সিঙ্ক্রোনাইজেশন এবং মিউটেক্স হ্যান্ডলিংয়ের বিস্তারিত আলোচনা করা হলো।
থ্রেড হলো একটি প্রক্রিয়ার মধ্যে কাজ করার স্বতন্ত্র একক। থ্রেড তৈরি করতে pthread_create()
ফাংশনটি ব্যবহার করা হয়।
#include <pthread.h>
int pthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine)(void *), void *arg);
thread
: নতুন থ্রেডের জন্য একটি পয়েন্টার।attr
: থ্রেডের অ্যাট্রিবিউট সেটিংস (সাধারণত NULL
পাঠানো হয়)।start_routine
: থ্রেডের জন্য শুরু হওয়া ফাংশন।arg
: শুরু হওয়া ফাংশনে পাস করা আর্গুমেন্ট (যদি প্রয়োজন হয়)।#include <stdio.h>
#include <pthread.h>
void *hello_world(void *arg) {
printf("Hello from thread!\n");
return NULL;
}
int main() {
pthread_t thread; // থ্রেড ডিক্লেয়ারেশন
// থ্রেড তৈরি
if (pthread_create(&thread, NULL, hello_world, NULL) != 0) {
perror("Thread creation failed");
return 1;
}
// থ্রেডের শেষ হওয়া পর্যন্ত অপেক্ষা করা
pthread_join(thread, NULL);
printf("Thread finished executing.\n");
return 0;
}
এখানে pthread_create()
ফাংশনটি একটি নতুন থ্রেড তৈরি করেছে, যা hello_world()
ফাংশনটি চালাবে। pthread_join()
ফাংশনটি থ্রেডটি শেষ হওয়া পর্যন্ত অপেক্ষা করে।
থ্রেড সিঙ্ক্রোনাইজেশন নিশ্চিত করে যে একাধিক থ্রেডের মধ্যে কোনও ডেটা কনফ্লিক্ট বা রেস কন্ডিশন (যখন একাধিক থ্রেড একই ডেটা এক্সেস করে) না ঘটে। সিঙ্ক্রোনাইজেশন বিভিন্ন মেকানিজমের মাধ্যমে করা হয়, যেমন মিউটেক্স (mutexes), কন্ডিশন ভেরিয়েবল, সেমাফোর ইত্যাদি।
#include <stdio.h>
#include <pthread.h>
pthread_mutex_t mutex; // মিউটেক্স ডিক্লেয়ারেশন
void *increment(void *arg) {
pthread_mutex_lock(&mutex); // মিউটেক্স লক করা
// critical section
printf("Thread is executing\n");
pthread_mutex_unlock(&mutex); // মিউটেক্স আনলক করা
return NULL;
}
int main() {
pthread_t threads[5];
// মিউটেক্স ইনিশিয়ালাইজ করা
pthread_mutex_init(&mutex, NULL);
// থ্রেড তৈরি করা
for (int i = 0; i < 5; i++) {
pthread_create(&threads[i], NULL, increment, NULL);
}
// থ্রেডের শেষে যাওয়া
for (int i = 0; i < 5; i++) {
pthread_join(threads[i], NULL);
}
// মিউটেক্স ডেস্ট্রয় করা
pthread_mutex_destroy(&mutex);
printf("All threads finished.\n");
return 0;
}
এখানে, pthread_mutex_lock()
এবং pthread_mutex_unlock()
ফাংশনগুলো ব্যবহার করে মিউটেক্স সিঙ্ক্রোনাইজেশন পরিচালনা করা হয়েছে।
মিউটেক্স (mutual exclusion) একটি সিঙ্ক্রোনাইজেশন প্রক্রিয়া যা একাধিক থ্রেডের মধ্যে একে অপরের কাছে একসাথে ডেটা অ্যাক্সেসে বাধা দেয়। এটি একটি লকিং মেকানিজম, যা নিশ্চিত করে যে এক সময়ে শুধুমাত্র একটি থ্রেড মেমোরি বা রিসোর্স অ্যাক্সেস করতে পারে।
#include <pthread.h>
int pthread_mutex_init(pthread_mutex_t *mutex, const pthread_mutexattr_t *attr);
int pthread_mutex_lock(pthread_mutex_t *mutex);
int pthread_mutex_unlock(pthread_mutex_t *mutex);
int pthread_mutex_destroy(pthread_mutex_t *mutex);
pthread_mutex_init()
: মিউটেক্স ইনিশিয়ালাইজ করে।pthread_mutex_lock()
: মিউটেক্সে লক করে, যদি অন্য কোনো থ্রেড মিউটেক্সে লক করে থাকে, তাহলে এটি অপেক্ষা করবে।pthread_mutex_unlock()
: মিউটেক্স আনলক করে, অন্য থ্রেডের জন্য লক উপলব্ধ করে।pthread_mutex_destroy()
: মিউটেক্স ধ্বংস করে।#include <stdio.h>
#include <pthread.h>
pthread_mutex_t mutex;
int counter = 0;
void *increment(void *arg) {
pthread_mutex_lock(&mutex); // মিউটেক্স লক করা
counter++;
printf("Counter value: %d\n", counter);
pthread_mutex_unlock(&mutex); // মিউটেক্স আনলক করা
return NULL;
}
int main() {
pthread_t threads[5];
pthread_mutex_init(&mutex, NULL); // মিউটেক্স ইনিশিয়ালাইজ
// থ্রেড তৈরি
for (int i = 0; i < 5; i++) {
pthread_create(&threads[i], NULL, increment, NULL);
}
// থ্রেডের শেষ হওয়া পর্যন্ত অপেক্ষা করা
for (int i = 0; i < 5; i++) {
pthread_join(threads[i], NULL);
}
pthread_mutex_destroy(&mutex); // মিউটেক্স ধ্বংস
return 0;
}
এখানে, counter
ভেরিয়েবলটি একাধিক থ্রেড দ্বারা এক্সেস করা হচ্ছে, কিন্তু মিউটেক্স pthread_mutex_lock()
এবং pthread_mutex_unlock()
দ্বারা সিঙ্ক্রোনাইজ করা হয়েছে, যাতে একাধিক থ্রেড একসাথে এই ভেরিয়েবলটি পরিবর্তন করতে না পারে। এর ফলে ডেটার সঠিকতা বজায় থাকে।
pthread_create()
ব্যবহার করে থ্রেড তৈরি করা হয়।pthread_mutex_lock()
এবং pthread_mutex_unlock()
ব্যবহৃত হয়। pthread_mutex_init()
দ্বারা মিউটেক্স ইনিশিয়ালাইজ করা হয় এবং pthread_mutex_destroy()
দ্বারা মিউটেক্স ধ্বংস করা হয়।থ্রেড ব্যবস্থাপনা এবং সিঙ্ক্রোনাইজেশন নিশ্চিত করতে এই কনসেপ্টগুলি অত্যন্ত গুরুত্বপূর্ণ, বিশেষত মাল্টিথ্রেডেড প্রোগ্রামে।
Deadlock এবং Race Condition দুটি গুরুত্বপূর্ণ সমস্যা যা মাল্টিথ্রেডেড প্রোগ্রামিংয়ে ঘটে। এই সমস্যাগুলি সাধারণত পারালাল এক্সিকিউশন এবং শেয়ার্ড রিসোর্স ব্যবহারের সময় ঘটে, এবং এটি সঠিকভাবে হ্যান্ডেল করা না হলে প্রোগ্রাম ক্র্যাশ হতে পারে বা অপ্রত্যাশিত আচরণ ঘটতে পারে। এদের প্রতিরোধের জন্য যথাযথ সিনক্রোনাইজেশন এবং লকারিং মেকানিজম ব্যবহার করা হয়।
Deadlock একটি পরিস্থিতি যেখানে দুটি বা তার বেশি থ্রেড বা প্রসেস একে অপরকে সম্পূর্ণ করতে বাধা দেয় কারণ তারা একে অপরের রিসোর্সের জন্য অপেক্ষা করছে। এক্ষেত্রে, প্রতিটি থ্রেড বা প্রসেস অন্য থ্রেড বা প্রসেসের সম্পূর্ণ করার জন্য অপেক্ষা করে এবং এর ফলে প্রোগ্রামটি স্থির হয়ে যায়।
Race Condition একটি সমস্যা যা ঘটে যখন একাধিক থ্রেড বা প্রসেস একটি শেয়ার্ড রিসোর্সে একসাথে প্রবেশ করে এবং এই অ্যাক্সেসকে সঠিকভাবে নিয়ন্ত্রিত না করা হলে এটি অপ্রত্যাশিত ফলাফল তৈরি করে। এটি সাধারণত তখন ঘটে যখন কোনো প্রসেস বা থ্রেড একটি রিসোর্সে কাজ করছে এবং অন্য একটি থ্রেড বা প্রসেস সেই রিসোর্সে পরিবর্তন আনতে পারে।
উদাহরণ:
pthread_mutex_t lock;
pthread_mutex_init(&lock, NULL);
pthread_mutex_lock(&lock); // রিসোর্স অ্যাক্সেসের আগে লক করুন
// রিসোর্সে কাজ করুন
pthread_mutex_unlock(&lock); // কাজ শেষ হলে লক খুলে দিন
উদাহরণ:
// উদাহরণ: Critical Section
void function() {
// Mutex লকারের মাধ্যমে একে একে একাধিক থ্রেডের অ্যাক্সেস নিয়ন্ত্রণ করা হচ্ছে
pthread_mutex_lock(&lock);
// শেয়ারড রিসোর্সে কাজ
pthread_mutex_unlock(&lock);
}
উদাহরণ:
sem_t sem;
sem_init(&sem, 0, 1); // সেমাফোরের প্রাথমিক মান 1
// একাধিক থ্রেড সেমাফোরের মাধ্যমে একে অপরের সাথে যোগাযোগ করবে
sem_wait(&sem); // রিসোর্সে প্রবেশের জন্য সেমাফোর পেতে হবে
// রিসোর্সে কাজ করুন
sem_post(&sem); // কাজ শেষ হলে সেমাফোর মুক্ত করুন
সমস্যা | বর্ণনা | প্রতিরোধের উপায় |
---|---|---|
Deadlock | একাধিক থ্রেড বা প্রসেস একে অপরকে সম্পূর্ণ করতে বাধা দেয়। | Lock Ordering, Deadlock Detection, Resource Allocation Graph |
Race Condition | একাধিক থ্রেড বা প্রসেস শেয়ার করা রিসোর্সে একসাথে প্রবেশ করে। | Mutex Locking, Critical Section, Semaphores, Atomic Operations |
কনকারেন্ট প্রোগ্রামিং (Concurrent Programming) হলো একাধিক কাজ বা প্রোগ্রাম অংশকে সমান্তরালভাবে (simultaneously) বা পাশাপাশি চালানোর কৌশল। এটি মাল্টি-থ্রেডিং, মাল্টি-প্রসেসিং এবং প্যারালাল প্রোগ্রামিংয়ের অন্তর্গত, যেখানে একাধিক কার্যক্রম একে অপরের সাথে সমান্তরালে (বা কিছু ক্ষেত্রে, একে অপরের সাথে মিশ্রিতভাবে) চলে। C প্রোগ্রামিং ভাষায় কনকারেন্ট প্রোগ্রামিংয়ের জন্য বেশ কিছু পদ্ধতি এবং লাইব্রেরি রয়েছে।
এখানে C তে কনকারেন্ট প্রোগ্রামিং প্রযুক্তি এবং তাদের ব্যবহার নিয়ে আলোচনা করা হবে।
মাল্টি-থ্রেডিং হলো একটাই প্রোগ্রাম বা প্রসেসের মধ্যে একাধিক থ্রেড তৈরি করা, যেখানে প্রতিটি থ্রেড একটি পৃথক কার্য সম্পাদন করে। C তে মাল্টি-থ্রেডিং সাধারণত pthread
লাইব্রেরি ব্যবহার করে পরিচালিত হয়। থ্রেডগুলি একে অপরের সাথে সমান্তরালভাবে কাজ করতে পারে, যা প্রোগ্রামের কর্মক্ষমতা এবং পারফরম্যান্স বাড়ায়।
pthread
লাইব্রেরি:pthread
(POSIX threads) হলো C এর জন্য একটি স্ট্যান্ডার্ড থ্রেড লাইব্রেরি, যা মাল্টি-থ্রেডিং পরিচালনার জন্য ব্যবহৃত হয়।
pthread_create()
: নতুন থ্রেড তৈরি করা।pthread_join()
: থ্রেডের কার্যক্রম সম্পূর্ণ হওয়া পর্যন্ত অপেক্ষা করা।pthread_exit()
: থ্রেডের কার্যক্রম শেষ হওয়া।#include <stdio.h>
#include <pthread.h>
// থ্রেডের কাজ
void* print_message(void* ptr) {
printf("Hello from thread!\n");
return NULL;
}
int main() {
pthread_t thread1, thread2;
// প্রথম থ্রেড তৈরি
pthread_create(&thread1, NULL, print_message, NULL);
// দ্বিতীয় থ্রেড তৈরি
pthread_create(&thread2, NULL, print_message, NULL);
// থ্রেডের কাজ শেষ হওয়া পর্যন্ত অপেক্ষা করা
pthread_join(thread1, NULL);
pthread_join(thread2, NULL);
printf("Hello from main thread!\n");
return 0;
}
এখানে দুটি থ্রেড তৈরি করা হয়েছে, এবং প্রতিটি থ্রেড "Hello from thread!" মেসেজ প্রিন্ট করবে।
শেয়ারড মেমরি হলো একাধিক প্রসেসের মধ্যে একে অপরের ডেটা শেয়ার করার পদ্ধতি। C তে শেয়ারড মেমরি ব্যবহারের জন্য shmget()
, shmat()
, shmdt()
, এবং shmctl()
ফাংশনগুলি ব্যবহার করা হয়।
shmget()
: শেয়ারড মেমরি তৈরি বা পাওয়ার জন্য ব্যবহৃত হয়।shmat()
: শেয়ারড মেমরিতে অ্যাক্সেস করার জন্য ব্যবহৃত হয়।shmdt()
: শেয়ারড মেমরি আনম্যাপ করার জন্য ব্যবহৃত হয়।#include <stdio.h>
#include <sys/ipc.h>
#include <sys/shm.h>
int main() {
key_t key = ftok("shmfile", 65);
int shmid = shmget(key, 1024, 0666|IPC_CREAT);
char *str = (char*) shmat(shmid, NULL, 0);
printf("Write data to shared memory: ");
gets(str); // ইউজার ইনপুট নেয়া
printf("Data written to shared memory: %s\n", str);
shmdt(str); // শেয়ারড মেমরি ডিসঅ্যাসোসিয়েট করা
return 0;
}
এই উদাহরণে, একটি প্রসেস শেয়ারড মেমরিতে ডেটা লেখে এবং অন্য প্রসেস সেই ডেটা পড়ে।
মেসেজ কিউ ব্যবহৃত হয় একাধিক প্রসেসের মধ্যে ডেটা আদান-প্রদান করার জন্য। C তে মেসেজ কিউ পরিচালনা করতে msgget()
, msgsnd()
, msgrcv()
, এবং msgctl()
ফাংশনগুলি ব্যবহৃত হয়।
msgget()
: একটি নতুন মেসেজ কিউ তৈরি বা খোঁজার জন্য ব্যবহৃত হয়।msgsnd()
: কিউতে একটি মেসেজ পাঠানোর জন্য ব্যবহৃত হয়।msgrcv()
: কিউ থেকে একটি মেসেজ গ্রহণ করার জন্য ব্যবহৃত হয়।#include <stdio.h>
#include <sys/ipc.h>
#include <sys/msg.h>
struct msg_buffer {
long msg_type;
char msg_text[100];
};
int main() {
key_t key = ftok("progfile", 65);
int msgid = msgget(key, 0666 | IPC_CREAT);
struct msg_buffer message;
// মেসেজ পাঠানো
message.msg_type = 1;
printf("Write message: ");
fgets(message.msg_text, sizeof(message.msg_text), stdin);
msgsnd(msgid, &message, sizeof(message), 0);
printf("Message sent: %s", message.msg_text);
// মেসেজ গ্রহণ করা
msgrcv(msgid, &message, sizeof(message), 1, 0);
printf("Message received: %s", message.msg_text);
msgctl(msgid, IPC_RMID, NULL); // মেসেজ কিউ নিষ্ক্রিয় করা
return 0;
}
এখানে, একটি প্রসেস মেসেজ পাঠাচ্ছে এবং অন্য প্রসেস মেসেজ গ্রহণ করছে।
সেমাফোর হলো একটি কনকারেন্ট প্রোগ্রামিং প্রযুক্তি যা একাধিক থ্রেড বা প্রসেসের মধ্যে সিঙ্ক্রোনাইজেশন নিশ্চিত করতে ব্যবহৃত হয়। এটি বিশেষ করে ক্রিটিকাল সেকশন বা একাধিক থ্রেডের মধ্যে ডেটা রেস কন্ডিশন এড়াতে সহায়ক।
C তে সেমাফোর ব্যবহারের জন্য sem_init()
, sem_wait()
, sem_post()
, এবং sem_destroy()
ফাংশনগুলি ব্যবহৃত হয়।
sem_wait()
: সেমাফোরের মান কমায় (যদি মান ইতিবাচক হয়) এবং থ্রেড বা প্রসেসকে ব্লক করে।sem_post()
: সেমাফোরের মান বাড়ায় এবং ব্লক করা থ্রেড বা প্রসেসকে মুক্ত করে।সি প্রোগ্রামিংয়ে কনকারেন্ট প্রোগ্রামিংয়ের কৌশলগুলি ব্যবহার করে বিভিন্ন কার্যক্রম একযোগে সম্পাদন করা যায়, যা প্রোগ্রামের পারফরম্যান্স এবং কার্যকারিতা উন্নত করতে সহায়ক।
common.read_more